#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>

int get_timezone(void)
{
  //获取系统时间的秒数 1970 01 01 00:00:00 到此时的一个秒数
  time_t t1 = time(NULL); //这个秒数，会有时区的偏移，基于当时区的一个秒数
  // printf("t1=%ld\n",t1);//t1是东8区的秒数

  //秒数转时间结构体
  struct tm *tp = gmtime(&t1); //这个函数输出的时间是基准时间，时区为0的基准时间
  time_t t2 = mktime(tp);      //把时间结构体 struct tm 转成 time_t 的秒数
  // printf("t2=%ld\n",t2);//t2是0时区的秒数
  // printf("t1-t2=%ld\n",(t1-t2)/36);//(本地时间 - 基准时间) 换算为小时

  return (t1 - t2) / 36;
}

int main(int argc, char const *argv[])
{
  struct stat st;

  if (argc != 2)
  {
    fprintf(stderr, "程序错误：运行程序时请带入参数(./28-stat filename)\n");
    exit(-1);
  }

  int ret = stat(argv[1], &st);
  if (ret < 0)
  {
    perror("stat");
    exit(-1);
  }

  // printf("st.st_dev=%ld\n",st.st_dev);//读取设备号
  // printf("st.st_ino=%ld\n",st.st_ino);//获取文件的inde唯一号
  printf("  文件: %s\n", argv[1]);        //输出文件名
  printf("  大小: %ld\t\t", st.st_size);  //输出文件大小（\t 加上一个tab按键，等于4个空格
  printf("块：%ld\t       ", st.st_blocks);  //输出文件占用的块
  printf("IO 块: %ld   ", st.st_blksize); //文件系统的块大小
  //printf("块：%ld\t", st.st_blksize);   //输出文件大小

  switch (st.st_mode & S_IFMT)
  {
  case S_IFBLK:
    printf("普通文件\n");
    break;
  case S_IFCHR:
    printf("字符设备\n");
    break;
  case S_IFDIR:
    printf("目录\n");
    break;
  case S_IFIFO:
    printf("管道文件\n");
    break;
  case S_IFLNK:
    printf("符号链接\n");
    break;
  case S_IFREG:
    printf("普通文件\n");
    break;
  case S_IFSOCK:
    printf("套接字\n");
    break;
  default:
    printf("unknown?\n");
    break;
  }

  printf("设备：%lxh/%ldd\t", st.st_dev, st.st_dev); //输出文件设备
  printf("Inode: %ld\t   ", st.st_ino);                 //输出文件的Inode号
  printf("硬链接: %ld\n", st.st_nlink);              //输出文件硬链接

  //保留st_mode的低9位，1个8进制的数占用3位
  printf("权限: (%#o/", st.st_mode & 0777); //输出文件的8进制权限
  switch (st.st_mode & S_IFMT)
  {
  case S_IFBLK:
    printf("b");
    break;
  case S_IFCHR:
    printf("c");
    break;
  case S_IFDIR:
    printf("d");
    break;
  case S_IFIFO:
    printf("p");
    break;
  case S_IFLNK:
    printf("l");
    break;
  case S_IFREG:
    printf("-");
    break;
  case S_IFSOCK:
    printf("s");
    break;
  default:
    printf("unknown?");
    break;
  }
  /********用户*********/
  //获取用户的可读权限
  if (st.st_mode & S_IRUSR)
    printf("r");
  else
    printf("-");

  //获取用户的可写权限
  if (st.st_mode & S_IWUSR)
    printf("w");
  else
    printf("-");

  //获取用户的可执行权限
  if (st.st_mode & S_IXUSR)
    printf("x");
  else
    printf("-");

  /**************组*******************************/
  //获取用户的可读权限
  if (st.st_mode & S_IRGRP)
    printf("r");
  else
    printf("-");

  //获取用户的可写权限
  if (st.st_mode & S_IWGRP)
    printf("w");
  else
    printf("-");

  //获取用户的可执行权限
  if (st.st_mode & S_IXGRP)
    printf("x");
  else
    printf("-");

  /**************其他用户的权限****************************/
  //获取用户的可读权限
  if (st.st_mode & S_IROTH)
    printf("r");
  else
    printf("-");

  //获取用户的可写权限
  if (st.st_mode & S_IWOTH)
    printf("w");
  else
    printf("-");

  //获取用户的可执行权限
  if (st.st_mode & S_IXOTH)
    printf("x");
  else
    printf("-");
  printf(")\t");

  /**************文件所有者****************************/
  struct passwd *pw = getpwuid(st.st_uid);
  printf(" Uid: (%d/\t%s)\t", st.st_uid, pw->pw_name);
  //struct tm *tmp = localtime(&st.st_atime); // st_atime 就是秒数

  struct group *grp = getgrgid(st.st_gid);
  printf(" Gid: (%d/\t%s)\n", st.st_gid, grp->gr_name);

  int timezone = get_timezone();
  struct tm *tmp = localtime(&st.st_atime); // st_atime 就是秒数

  printf("最近访问: %04d-%02d-%02d %02d:%02d:%02d.%09ld %+05d\n", tmp->tm_year + 1900,
         tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec,
         st.st_atim.tv_nsec, timezone);

  tmp = localtime(&st.st_mtime); // st_atime 就是秒数
  printf("最近更改: %04d-%02d-%02d %02d:%02d:%02d.%09ld %+05d\n", tmp->tm_year + 1900,
         tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec,
         st.st_mtim.tv_nsec,timezone);

  tmp = localtime(&st.st_ctime); // st_atime 就是秒数
  printf("最近改动: %04d-%02d-%02d %02d:%02d:%02d.%09ld %+05d\n", tmp->tm_year + 1900,
         tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec,
         st.st_ctim.tv_nsec, timezone);

  printf("创建时间：- \n");

  return 0;
}
